home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
public
/
bit
/
src
/
pedit.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
16KB
|
680 lines
/*
* $Id: pedit.c,v 0.91 1994/02/20 00:53:22 zhao Pre-Release $
*
*. This file is part of BIT shareware package. After the two weeks of
* free evaluation period, you are encouraged (required) to register
* your copy for a small registration fee, which is $35 for personal use
* and $50 for commercial, government and institutional use.
*
* Copyright(c) 1993, 1994 by T.C. Zhao.
* All rights reserved.
*
* Permission to use, copy, and distribute this software in its entirety
* for non-commercial purposes is hereby granted, provided that the
* above shareware and copyright notices and this permission notice
* appear in all copies and their documentation.
*
* This software may be modified for your own use, but modified versions
* may not be distributed without prior consent of the author.
*
* This software is provided "as is" without expressed or implied
* warranty of any kind.
*
*.
*
* Purpose:
* Edit an individual pixel or a group of pixels.
*
*/
#if !defined(lint) && defined(F_ID)
char *id_pe = "$Id: pedit.c,v 0.91 1994/02/20 00:53:22 zhao Pre-Release $";
#endif
#include "bit.h"
#include "extern.h"
/**************** Local variables *********************************/
static int dx = 30, dy = 30; /* edit region */
static int xi, yi; /* lower left corner of region */
static long pewin = -1; /* edit window */
static long pewinx, pewiny; /* window lower left corner */
static void *pemat; /* generic matrix */
static rgba_t **cpmat; /* cpack matrix */
static ci_t **cmmat; /* color index matrix */
static int pxi = -1, pyi; /* currently selected pixel in matrix */
static int pc[4]; /* current pixel color */
static int spc[4]; /* pixel color when first selected */
static int gridcol[4]; /* color marks of the grid */
static int markcol = 1; /* colors used to mark the selection */
/****************** Local functions ********************************/
static int pe_init(IPTR); /* initialize */
static void pe_cleanup(void); /* finish */
static void pe_set(IPTR); /* set pix's color */
static void pe_select(IPTR); /* select a pix to edit */
static int pe_keybd(int); /* handle keyboard */
static int pe_popup(IPTR); /* handle pop-up */
static void pe_altkey(IPTR); /* handle ALTKEY */
static void addto_dirty_pool(void);
static int pe_wm_handler(IPTR, int /* wme */ );
static int draw_pewin(IPTR, int /* win */ );
static void mark_selection(int, int, int);
/***************************************************************
* it would appear that sometines, a mouse Q event is left after
* a getbutton call. Eat it
****************************************************************/
static void
eat_qevent(long dev)
{
short val;
while (fl_qtest() == dev)
(void) fl_qread(&val);
}
/*********************************************************************
* Global entry point from control panel
*********************************************************************/
int
pixel_edit(IPTR im)
{
short val;
int done = 0;
/* get the editing region and image matrix */
if (pe_init(im) < 0)
return -1;
/* how to handle redraw of pewin */
install_multiw_handler(draw_pewin);
install_wm_handler(pe_wm_handler);
pe_wm_handler(im, 0); /* initialize position */
/* looping until ESC key or done/cancel from popup entry */
while (!done)
{
/*
* this might save some CPU cycles since bit_qread never block
* while fl_do_forms does
*/
while (!fl_qtest())
fl_do_forms();
/* service all redraw and other Q events */
switch (bit_qread(&val))
{
case MIDDLEMOUSE:
if (val)
pe_set(im);
break;
case LEFTALTKEY:
case RIGHTALTKEY:
if (val)
pe_altkey(im);
break;
case LEFTMOUSE:
if (val)
(altkey_down ? pe_set : pe_select) (im);
break;
case MENUBUTTON:
if (val)
done = pe_popup(im);
break;
case KEYBD:
done = pe_keybd(val);
break;
}
}
/* we want to the change to be made to the image in core */
if (done > 0)
{ /* overwrite */
put_subimage(im, pemat, make_rect(xi, yi, dx, dy), 1);
dbl_rect_redraw(im, xi, yi, dx, dy);
}
pe_cleanup();
return 0;
}
/********* Clean up **********************/
static void
pe_cleanup(void)
{
short val;
hide_getcolor();
rubber_finish();
remove_multiw_handler(draw_pewin);
remove_wm_handler(pe_wm_handler);
/* handle this redraw first */
(void) bit_qread(&val);
winclose(pewin);
/* fake a dirty rectangle */
addto_dirty_pool();
/* signal closing of pixel edit window */
pewin = -1;
clear_over_pup();
fl_activate_all_forms();
}
/******************************************************************
* draw a small cross at the currently selected pixle
******************************************************************/
static void
mark_selection(int x, int y, int col)
{
if (x < 0 || pewin <= 0)
return;
if (winget() != pewin)
winset(pewin);
switch_frame_buffer();
color(col);
/* a plus rotated 45 */
gl_plus(x + pezx / 2, y + pezy / 2,
pezx - 2, pezy - 2, 0, 450); /* cross */
drawmode(NORMALDRAW);
}
/*********************************************************************
* make grid lines. gx and gy are step size
*********************************************************************/
static void
make_grid(long win, int gcol[], int gx, int gy)
{
long owin = winget();
int x, y;
long xm, ym;
winset(win);
getsize(&xm, &ym);
Color(Pack(gcol[0], gcol[1], gcol[2]), gcol[3]);
for (x = gx; x < xm; x += gx)
draw_line(x, 0, x, ym);
for (y = gy; y < ym; y += gy)
draw_line(0, y, xm, y);
if (owin > 0 && owin != win)
winset(owin);
}
/**************************************************************
* Add the pewin to the dirty pool so that the repaint driver won't
* do a full redraw
*************************************************************/
static void
addto_dirty_pool(void)
{
int bw = 13;
add_d_rect(pewinx - bw, pewiny - bw,
pezx * dx + 2 * bw, pezy * dy + 4 * bw);
}
/***************************************************************
* called by repaint thru extra_paint function pointer to repair
* any damages to pewin.
****************************************************************/
/* ARGSUSED */
static int
draw_pewin(IPTR im, int val)
{
long owin = winget();
static long xm, ym, ox, oy;
/* local call pass val == -1, dispatcher calls with val == pewin */
if (pewin <= 0 || (val > 0 && val != pewin))
return -1;
if (owin != pewin)
winset(pewin);
if (val > 0)
{
getsize(&xm, &ym);
getorigin(&pewinx, &pewiny);
reshapeviewport();
ortho2(-0.5, xm - 0.5, -0.5, ym - 0.5);
switch_frame_buffer();
color(0);
clear();
drawmode(NORMALDRAW);
/* add dirty pool only if we know for sure that pewin moved */
if (ox - pewinx || oy - pewiny)
addto_dirty_pool();
}
ox = pewinx;
oy = pewiny;
/* do the raster */
rectzoom((float) pezx, (float) pezy);
if (IS_CPACK(im))
lrectwrite(0, 0, dx - 1, dy - 1, cpmat[0]);
else
rectwrite(0, 0, dx - 1, dy - 1, cmmat[0]);
rectzoom(1.0, 1.0);
/* also generate grid */
if (val > 0)
{
make_grid(pewin, gridcol, pezx, pezy);
}
mark_selection(pxi * pezx, pyi * pezy, markcol);
if (owin != pewin && is_valid_win(owin))
set_current_window(owin);
return 0;
}
/*******************************************************************
* draw a single pixel at (px, py) in matrix
*******************************************************************/
static void
draw_pixel(IPTR im, int py, int px)
{
long owin = winget();
int ppx = px * pezx, ppy = py * pezy;
set_current_window(pewin);
rectzoom(pezx, pezy);
if (IS_CI(im))
{
rectwrite(ppx, ppy, ppx, ppy, ((ci_t **) pemat)[py] + px);
}
else
{
lrectwrite(ppx, ppy, ppx, ppy, ((rgba_t **) pemat)[py] + px);
}
rectzoom(1., 1.);
if (owin > 0)
set_current_window(owin);
}
/*****************************************************************
* Get a rectangular region of the image, which will be
* the raster we will be editing
*****************************************************************/
static int
get_edit_matrix(IPTR im)
{
if (pemat)
free_mat(pemat);
if (!(pemat = get_subimage(im, xi, yi, dx, dy)))
{
Bark("PEInit", "Unable to get submatrix");
return -1;
}
cpmat = pemat;
cmmat = pemat;
return 0;
}
static void
open_pewin(IPTR im, int ini)
{
int pww = pezx * dx - 1;
int pwh = pezy * dy - 1;
int gx = getgdesc(GD_XPMAX) - 15;
int gy = getgdesc(GD_YPMAX) - 40;
if (pewin > 0)
return;
if (ini)
/* place it on upper-right corner */
prefposition(gx - pww, gx, gy - pwh, gy);
else
prefposition(pewinx, pewinx + pww, pewiny, pewiny + pwh);
pewin = winopen("PixelEdit");
getorigin(&pewinx, &pewiny);
set_cursor(pewin, CUR_S_CROSS);
set_default_cursor(pewin, CUR_S_CROSS);
if (IS_CPACK(im))
{
RGBmode();
gconfig();
}
}
/***************************************************************
* select the editing region with a moving rubber band.
* continuing zooming and moving until a mouse click
***************************************************************/
static int
pe_init(IPTR im)
{
short val;
long dev;
int done;
/* we must limit the region size */
if (dx > im->w)
dx = im->w;
if (dy > im->h)
dx = im->h;
set_rubber_bounds(1, im->xi, im->yi, im->w, im->h);
set_rubber_obj(RB_RECT);
deactivate_all_forms();
xi = im->xi + im->w / 2;
yi = im->yi + im->h / 2;
if (pewin < 0)
{
open_pewin(im, 1);
}
set_current_window(win_id);
/* warp the mouse */
set_mouse(xi + win_xo, yi + win_yo);
/* place the rubber */
do
{
done = 0;
dev = rubber_cursor(win_id, &val, &xi, &yi, dx, dy, 1);
switch ((dev = bit_handle_event(dev, val)))
{
case LEFTMOUSE:
case MIDDLEMOUSE:
done = val;
break;
default:
/* must've been moved */
if (get_edit_matrix(im) < 0)
return -1;
draw_pewin(im, -1);
}
}
while (!done);
/* Final matrix */
if (get_edit_matrix(im) < 0)
return -1;
draw_pewin(im, pewin); /* last time to get grid */
eat_qevent(MIDDLEMOUSE);
eat_qevent(LEFTMOUSE);
return 0;
}
/*******************************************************
* copy a pixel in RGB CI format
******************************************************/
static void
cp_pixel(int *des, int *src)
{
*des++ = *src++;
*des++ = *src++;
*des++ = *src++;
*des = *src;
}
/*****************************************************************
* main control thru popup: Return -1 for cancel, 1 for Done
* 0: no action
****************************************************************/
static int
pe_popup(IPTR im)
{
static long pemenu = -1;
int ret = 0;
int cc;
char *mentry =
"PixEdit%t|Help%x5|MarkCol%x10|GridCol%x12|Repeat%x18|"
"Cancel%x20|Done%x50";
if (pemenu < 0)
pemenu = defpup(mentry);
switch (dopup(pemenu))
{
case 5:
help_cb(0, HELP_PEDIT);
break;
case 10:
++markcol;
markcol %= over_pup_colors;
mark_selection(pxi * pezx, pyi * pezy, markcol);
break;
case 12: /* grid color */
cc = (~gridcol[0]) & PCMAXV;
gridcol[0] = gridcol[1] = gridcol[2] = cc;
if (IS_CI(im))
gridcol[3] = cmap_closematch(im->cmap,
gridcol[0], gridcol[1], gridcol[2]);
make_grid(pewin, gridcol, pezx, pezy);
break;
case 18: /* do to all pixels having the selected color */
if (IS_CI(im))
modify_ci_pixel(cmmat[0], dx * dy, spc[3], pc[3], 0);
else
modify_cpack_pixel(cpmat[0], dx * dy,
Pack(spc[0], spc[1], spc[2]),
Pack(pc[0], pc[1], pc[2]), 0);
draw_pewin(im, pewin);/* one to get grid on */
break;
case 20: /* cancel */
ret = -1;
break;
case 50: /* save & return */
ret = 1;
break;
}
return ret;
}
/**************************************************************
* get pixel position under mouse
***************************************************************/
static void
get_pix_pos(int *x, int *y)
{
int mx, my;
int px, py;
get_mouse(&mx, &my);
mx -= pewinx;
my -= pewiny;
/* figure out where the pixel should be */
px = (mx / pezx);
py = (my / pezy);
/* check if within pewin (0, dx-1, 0, dy-1) */
if (px >= 0 && px <= dx - 1 && py >= 0 && py <= dy - 1)
{
*x = px;
*y = py;
}
}
/**************************************************************
* what to do if color changes
**************************************************************/
static void
handle_color_change(int c[])
{
pack_pixel(imgptr, pemat, pyi, pxi, c);
draw_pixel(imgptr, pyi, pxi);
}
/*****************************************************************
* Select a new pixel to edit
****************************************************************/
static void
pe_select(IPTR im)
{
/* remove last mark */
mark_selection(pxi * pezx, pyi * pezy, 0);
/* making a new selection and mark it */
get_pix_pos(&pxi, &pyi);
mark_selection(pxi * pezx, pyi * pezy, markcol);
pick_pixel(im, pemat, pyi, pxi, spc);
cp_pixel(pc, spc);
set_getcolor_cb(handle_color_change);
eat_qevent(LEFTMOUSE);
/* immediate returns */
get_color(im, pc, 0);
}
/*******************************************************************
* Set pixel or pixels to last selected color
*******************************************************************/
static void
pe_set(IPTR im)
{
int reqalt;
set_current_window(pewin);
reshapeviewport();
/* initiated by altkey */
reqalt = altkey_down;
/* turn off last mark */
mark_selection(pxi * pezx, pyi * pezy, 0);
do
{
get_pix_pos(&pxi, &pyi);
pack_pixel(im, pemat, pyi, pxi, pc);
draw_pixel(im, pyi, pxi);
}
while (mouse_down && (!reqalt || (reqalt && altkey_down)));
/* show it at current location */
mark_selection(pxi * pezx, pyi * pezy, markcol);
}
/******************************************************************
* Keyboard handler
******************************************************************/
static int
pe_keybd(int val)
{
int ret = 0;
switch (val)
{
case 27:
ret = -1;
break;
}
return ret;
}
/*******************************************************************
* handle main window resize, reposition events
*******************************************************************/
/*ARGSUSED*/
static int
pe_wm_handler(IPTR im, int wme)
{
static int lxi, lyi, lwx, lwy;
if (wme)
{
/* remove the old rectangle */
rubber_new(win_id, xi - (win_xo - lwx),
yi - (win_yo - lwy), dx, dy, 0);
xi += im->xi - lxi;
yi += im->yi - lyi;
/* show at new location */
rubber_new(win_id, xi, yi, dx, dy, 1);
}
lxi = im->xi;
lyi = im->yi;
lwx = win_xo;
lwy = win_yo;
return 0;
}
/****************************************************************
* LEFT alt key is down
****************************************************************/
static void
pe_altkey(IPTR im)
{
int oc[3];
get_cursor_color(oc);
set_cursor_color(pc);
set_cursor(pewin, CUR_S_FRECT);
do
{
if (getbutton(LEFTMOUSE) || getbutton(MIDDLEMOUSE))
{
pe_set(im);
}
}
while (altkey_down);
eat_qevent(LEFTMOUSE);
set_cursor_color(oc);
reset_cursor(pewin);
}
/*************************************************************
* for iconify routines
************************************************************/
static int iconified;
void
pewin_iconify(void)
{
if (pewin > 0)
{
winclose(pewin);
pewin = -1;
iconified = 1;
}
}
void
pewin_de_iconify(void)
{
if (iconified)
{
open_pewin(imgptr, 0);
draw_pewin(imgptr, pewin);
iconified = 0;
}
}